import org.jd.core.v1.ClassFileToJavaSourceDecompiler;
import org.jd.core.v1.api.loader.Loader;
import org.jd.core.v1.api.loader.LoaderException;
import org.jd.core.v1.api.printer.Printer;
import org.junit.Test;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class DeCompiler {
    @Test
    public void jdTest() throws Exception {
        System.out.println("deCompile begin");
//        System.out.println("classPath:" + classPath);
        Loader loader = new Loader() {
            @Override
            public byte[] load(String internalName) throws LoaderException {
                byte[] codeByte = null;
                InputStream is = this.getClass().getResourceAsStream(internalName + ".class");

                if (is == null) {
                    return null;
                } else {
                    try (InputStream in=is; ByteArrayOutputStream out=new ByteArrayOutputStream()) {
                        byte[] buffer = new byte[1024];
                        int read = in.read(buffer);

                        while (read > 0) {
                            out.write(buffer, 0, read);
                            read = in.read(buffer);
                        }

                        return out.toByteArray();
                    } catch (IOException e) {
                        throw new LoaderException(e);
                    }
                }

//                System.out.println("load codeByte");
//                return codeByte;
            }

            @Override
            public boolean canLoad(String internalName) {
//                return this.getClass().getResource("/" + internalName + ".class") != null;
                return true;
            }
        };
        Printer printer = new Printer() {
            private static final String TAB = "  ";
            private static final String NEWLINE = "\n";

            private int indentationCount = 0;
            private final StringBuilder sb = new StringBuilder();

            @Override
            public String toString() {
                return sb.toString();
            }

            @Override
            public void start(int maxLineNumber, int majorVersion, int minorVersion) {
                System.out.println("start");
            }

            @Override
            public void end() {
                System.out.println("end");
            }

            @Override
            public void printText(String text) {
                System.out.println("printText");
                sb.append(text);
            }

            @Override
            public void printNumericConstant(String constant) {
                System.out.println("printNumericConstant");
                sb.append(constant);
            }

            @Override
            public void printStringConstant(String constant, String ownerInternalName) {
                System.out.println("printStringConstant");
                sb.append(constant);
            }

            @Override
            public void printKeyword(String keyword) {
                System.out.println("printKeyword");
                sb.append(keyword);
            }

            @Override
            public void printDeclaration(int type, String internalTypeName, String name, String descriptor) {
                System.out.println("printDeclaration");
                sb.append(name);
            }

            @Override
            public void printReference(int type, String internalTypeName, String name, String descriptor, String ownerInternalName) {
                System.out.println("printReference");
                sb.append(name);
            }

            @Override
            public void indent() {

                System.out.println("indent");
                this.indentationCount++;
            }

            @Override
            public void unindent() {
                System.out.println("unindent");
                this.indentationCount--;
            }

            @Override
            public void startLine(int lineNumber) {
                System.out.println("startLine");
                sb.append(TAB.repeat(Math.max(0, indentationCount)));
            }

            @Override
            public void endLine() {
                System.out.println("endLine");
                sb.append(NEWLINE);
            }

            @Override
            public void extraLine(int count) {
                System.out.println("extraLine");
                while (count-- > 0) sb.append(NEWLINE);
            }

            @Override
            public void startMarker(int type) {
                System.out.println("startMarker");
            }

            @Override
            public void endMarker(int type) {
                System.out.println("endMarker");
            }
        };
        ClassFileToJavaSourceDecompiler decompiler = new ClassFileToJavaSourceDecompiler();
        try {
            System.out.println("before decompile");
            decompiler.decompile(loader, printer, "ClassLoaderTest");

            System.out.println("after decompile");
        } catch (Exception e) {
            System.out.println("Exception:"+e);
        }
        String source = printer.toString();
        System.out.println("source:"+source);

    }
}
